home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1992, Brian Berliner and Jeff Polk
- * Copyright (c) 1989-1992, Brian Berliner
- *
- * You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.3 kit.
- *
- * "import" checks in the vendor release located in the current directory into
- * the CVS source repository. The CVS vendor branch support is utilized.
- *
- * At least three arguments are expected to follow the options:
- * repository Where the source belongs relative to the CVSROOT
- * VendorTag Vendor's major tag
- * VendorReleTag Tag for this particular release
- *
- * Additional arguments specify more Vendor Release Tags.
- */
-
- #include "cvs.h"
-
- #ifndef lint
- static char rcsid[] = "@(#)import.c 1.52 92/03/31";
- #endif
-
- #define FILE_HOLDER ".#cvsxxx"
-
- #if __STDC__
- static char *get_comment (char *user);
- static int add_rcs_file (char *message, char *rcs, char *user, char *vtag,
- int targc, char *targv[]);
- static int expand_at_signs (char *buf, off_t size, FILE *fp);
- static int add_rev (char *message, char *rcs, char *vfile, char *vers);
- static int add_tags (char *rcs, char *vfile, char *vtag, int targc,
- char *targv[]);
- static int import_descend (char *message, char *vtag, int targc, char *targv[]);
- static int import_descend_dir (char *message, char *dir, char *vtag,
- int targc, char *targv[]);
- static int process_import_file (char *message, char *vfile, char *vtag,
- int targc, char *targv[]);
- static int update_rcs_file (char *message, char *vfile, char *vtag, int targc,
- char *targv[]);
- static void add_log (int ch, char *fname);
- #else
- static int import_descend ();
- static int process_import_file ();
- static int update_rcs_file ();
- static int add_rev ();
- static int add_tags ();
- static char *get_comment ();
- static int add_rcs_file ();
- static int expand_at_signs ();
- static void add_log ();
- static int import_descend_dir ();
- #endif /* __STDC__ */
-
- static int repos_len;
- static char vhead[50];
- static char vbranch[50];
- static FILE *logfp;
- static char repository[PATH_MAX];
- static int conflicts;
-
- static char *import_usage[] =
- {
- "Usage: %s %s [-Qq] [-I ign] [-m msg] [-b branch]\n",
- " repository vendor-tag release-tags...\n",
- "\t-Q\tReally quiet.\n",
- "\t-q\tSomewhat quiet.\n",
- "\t-I ign\tMore files to ignore (! to reset).\n",
- "\t-b bra\tVendor branch id.\n",
- "\t-m msg\tLog message.\n",
- NULL
- };
-
- int
- import (argc, argv)
- int argc;
- char *argv[];
- {
- char message[MAXMESGLEN];
- char tmpfile[L_tmpnam+1];
- char *cp;
- int i, c, msglen, err;
- List *ulist;
- Node *p;
-
- if (argc == -1)
- usage (import_usage);
-
- ign_setup ();
-
- (void) strcpy (vbranch, CVSBRANCH);
- message[0] = '\0';
- optind = 1;
- while ((c = gnu_getopt (argc, argv, "Qqb:m:I:")) != -1)
- {
- switch (c)
- {
- case 'Q':
- really_quiet = 1;
- /* FALL THROUGH */
- case 'q':
- quiet = 1;
- break;
- case 'b':
- (void) strcpy (vbranch, optarg);
- break;
- case 'm':
- #ifdef FORCE_USE_EDITOR
- use_editor = TRUE;
- #else
- use_editor = FALSE;
- #endif
- if (strlen (optarg) >= (sizeof (message) - 1))
- {
- error (0, 0, "warning: message too long; truncated!");
- (void) strncpy (message, optarg, sizeof (message));
- message[sizeof (message) - 2] = '\0';
- }
- else
- (void) strcpy (message, optarg);
- break;
- case 'I':
- ign_add (optarg, 0);
- break;
- case '?':
- default:
- usage (import_usage);
- break;
- }
- }
- argc -= optind;
- argv += optind;
- if (argc < 3)
- usage (import_usage);
-
- for (i = 1; i < argc; i++) /* check the tags for validity */
- RCS_check_tag (argv[i]);
-
- /* XXX - this should be a module, not just a pathname */
- if (argv[0][0] != '/')
- {
- if (CVSroot == NULL)
- {
- error (0, 0, "missing CVSROOT environment variable\n");
- error (1, 0, "Set it or specify the '-d' option to %s.",
- program_name);
- }
- (void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
- repos_len = strlen (CVSroot);
- }
- else
- {
- (void) strcpy (repository, argv[0]);
- repos_len = 0;
- }
-
- /*
- * Consistency checks on the specified vendor branch. It must be
- * composed of only numbers and dots ('.'). Also, for now we only
- * support branching to a single level, so the specified vendor branch
- * must only have two dots in it (like "1.1.1").
- */
- for (cp = vbranch; *cp != '\0'; cp++)
- if (!isdigit (*cp) && *cp != '.')
- error (1, 0, "%s is not a numeric branch", vbranch);
- if (numdots (vbranch) != 2)
- error (1, 0, "Only branches with two dots are supported: %s", vbranch);
- (void) strcpy (vhead, vbranch);
- cp = rindex (vhead, '.');
- *cp = '\0';
- if (use_editor)
- do_editor ((char *) NULL, message, repository, (List *) NULL);
- msglen = strlen (message);
- if (msglen == 0 || message[msglen - 1] != '\n')
- {
- message[msglen] = '\n';
- message[msglen + 1] = '\0';
- }
-
- /*
- * Make all newly created directories writable. Should really use a more
- * sophisticated security mechanism here.
- */
- (void) umask (2);
- make_directories (repository);
-
- /* Create the logfile that will be logged upon completion */
- if ((logfp = fopen (tmpnam (tmpfile), "w+")) == NULL)
- error (1, errno, "cannot create temporary file `%s'", tmpfile);
- (void) unlink (tmpfile); /* to be sure it goes away */
- (void) fprintf (logfp, "\nVendor Tag:\t%s\n", argv[1]);
- (void) fprintf (logfp, "Release Tags:\t");
- for (i = 2; i < argc; i++)
- (void) fprintf (logfp, "%s\n\t\t", argv[i]);
- (void) fprintf (logfp, "\n");
-
- /* Just Do It. */
- err = import_descend (message, argv[1], argc - 2, argv + 2);
- if (conflicts)
- {
- if (!really_quiet)
- {
- (void) printf ("\n%d conflicts created by this import.\n",
- conflicts);
- (void) printf ("Use the following command to help the merge:\n\n");
- (void) printf ("\t%s checkout -j%s:yesterday -j%s %s\n\n",
- program_name, argv[1], argv[1], argv[0]);
- }
-
- (void) fprintf (logfp, "\n%d conflicts created by this import.\n",
- conflicts);
- (void) fprintf (logfp,
- "Use the following command to help the merge:\n\n");
- (void) fprintf (logfp, "\t%s checkout -j%s:yesterday -j%s %s\n\n",
- program_name, argv[1], argv[1], argv[0]);
- }
- else
- {
- if (!really_quiet)
- (void) printf ("\nNo conflicts created by this import\n\n");
- (void) fprintf (logfp, "\nNo conflicts created by this import\n\n");
- }
-
- /*
- * Write out the logfile and clean up.
- */
- ulist = getlist ();
- p = getnode ();
- p->type = UPDATE;
- p->delproc = update_delproc;
- p->key = xstrdup ("- Imported sources");
- p->data = (char *) T_TITLE;
- (void) addnode (ulist, p);
- Update_Logfile (repository, message, vbranch, logfp, ulist);
- dellist (&ulist);
- (void) fclose (logfp);
- return (err);
- }
-
- /*
- * process all the files in ".", then descend into other directories.
- */
- static int
- import_descend (message, vtag, targc, targv)
- char *message;
- char *vtag;
- int targc;
- char *targv[];
- {
- DIR *dirp;
- struct direct *dp;
- int err = 0;
- int has_dirs = 0;
-
- /* first, load up any per-directory ignore lists */
- ign_add_file (CVSDOTIGNORE, 1);
-
- if ((dirp = opendir (".")) == NULL)
- {
- err++;
- }
- else
- {
- while ((dp = readdir (dirp)) != NULL)
- {
- if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0)
- continue;
- if (ign_name (dp->d_name))
- {
- add_log ('I', dp->d_name);
- continue;
- }
- if (isdir (dp->d_name))
- {
- has_dirs = 1;
- }
- else
- {
- if (islink (dp->d_name))
- {
- add_log ('L', dp->d_name);
- err++;
- }
- else
- {
- err += process_import_file (message, dp->d_name,
- vtag, targc, targv);
- }
- }
- }
- (void) closedir (dirp);
- }
- if (has_dirs)
- {
- if ((dirp = opendir (".")) == NULL)
- err++;
- else
- {
- while ((dp = readdir (dirp)) != NULL)
- {
- if (ign_name (dp->d_name) || !isdir (dp->d_name))
- continue;
- err += import_descend_dir (message, dp->d_name,
- vtag, targc, targv);
- }
- (void) closedir (dirp);
- }
- }
- return (err);
- }
-
- /*
- * Process the argument import file.
- */
- static int
- process_import_file (message, vfile, vtag, targc, targv)
- char *message;
- char *vfile;
- char *vtag;
- int targc;
- char *targv[];
- {
- char attic_name[PATH_MAX];
- char rcs[PATH_MAX];
-
- (void) sprintf (rcs, "%s/%s%s", repository, vfile, RCSEXT);
- if (!isfile (rcs))
- {
- (void) sprintf (attic_name, "%s/%s/%s%s", repository, CVSATTIC,
- vfile, RCSEXT);
- if (!isfile (attic_name))
- {
-
- /*
- * A new import source file; it doesn't exist as a ,v within the
- * repository nor in the Attic -- create it anew.
- */
- add_log ('N', vfile);
- return (add_rcs_file (message, rcs, vfile, vtag, targc, targv));
- }
- }
-
- /*
- * an rcs file exists. have to do things the official, slow, way.
- */
- return (update_rcs_file (message, vfile, vtag, targc, targv));
- }
-
- /*
- * The RCS file exists; update it by adding the new import file to the
- * (possibly already existing) vendor branch.
- */
- static int
- update_rcs_file (message, vfile, vtag, targc, targv)
- char *message;
- char *vfile;
- char *vtag;
- int targc;
- char *targv[];
- {
- Vers_TS *vers;
- char letter;
- int ierrno;
-
- vers = Version_TS (repository, (char *) NULL, vbranch, (char *) NULL, vfile,
- 1, 0, (List *) NULL, (List *) NULL);
- if (vers->vn_rcs != NULL)
- {
- char xtmpfile[50];
- int different;
- int retcode = 0;
-
- /* XXX - should be more unique */
- (void) sprintf (xtmpfile, "/tmp/%s", FILE_HOLDER);
-
- /*
- * The rcs file does have a revision on the vendor branch. Compare
- * this revision with the import file; if they match exactly, there
- * is no need to install the new import file as a new revision to the
- * branch. Just tag the revision with the new import tags.
- *
- * This is to try to cut down the number of "C" conflict messages for
- * locally modified import source files.
- */
- #ifdef HAVE_RCS5
- run_setup ("%s%s -q -f -r%s -p -ko", Rcsbin, RCS_CO, vers->vn_rcs);
- #else
- run_setup ("%s%s -q -f -r%s -p", Rcsbin, RCS_CO, vers->vn_rcs);
- #endif
- run_arg (vers->srcfile->path);
- if ((retcode = run_exec (RUN_TTY, xtmpfile, RUN_TTY,
- RUN_NORMAL|RUN_REALLY)) != 0)
- {
- ierrno = errno;
- fperror (logfp, 0, retcode == -1 ? ierrno : 0,
- "ERROR: cannot co revision %s of file %s", vers->vn_rcs,
- vers->srcfile->path);
- error (0, retcode == -1 ? ierrno : 0,
- "ERROR: cannot co revision %s of file %s", vers->vn_rcs,
- vers->srcfile->path);
- (void) unlink_file (xtmpfile);
- return (1);
- }
- different = xcmp (xtmpfile, vfile);
- (void) unlink_file (xtmpfile);
- if (!different)
- {
- int retval = 0;
-
- /*
- * The two files are identical. Just update the tags, print the
- * "U", signifying that the file has changed, but needs no
- * attention, and we're done.
- */
- if (add_tags (vers->srcfile->path, vfile, vtag, targc, targv))
- retval = 1;
- add_log ('U', vfile);
- freevers_ts (&vers);
- return (retval);
- }
- }
-
- /* We may have failed to parse the RCS file; check just in case */
- if (vers->srcfile == NULL || add_rev (message, vers->srcfile->path,
- vfile, vers->vn_rcs) ||
- add_tags (vers->srcfile->path, vfile, vtag, targc, targv))
- {
- freevers_ts (&vers);
- return (1);
- }
-
- if (vers->srcfile->branch == NULL ||
- strcmp (vers->srcfile->branch, vbranch) != 0)
- {
- conflicts++;
- letter = 'C';
- }
- else
- letter = 'U';
- add_log (letter, vfile);
-
- freevers_ts (&vers);
- return (0);
- }
-
- /*
- * Add the revision to the vendor branch
- */
- static int
- add_rev (message, rcs, vfile, vers)
- char *message;
- char *rcs;
- char *vfile;
- char *vers;
- {
- int locked, status, ierrno;
- int retcode = 0;
-
- if (noexec)
- return (0);
-
- locked = 0;
- if (vers != NULL)
- {
- run_setup ("%s%s -q -l%s", Rcsbin, RCS, vbranch);
- run_arg (rcs);
- if ((retcode = run_exec (RUN_TTY, DEVNULL, DEVNULL, RUN_NORMAL)) == 0)
- locked = 1;
- else if (retcode == -1)
- {
- error (0, errno, "fork failed");
- return (1);
- }
- }
- if (link_file (vfile, FILE_HOLDER) < 0)
- {
- if (errno == EEXIST)
- {
- (void) unlink_file (FILE_HOLDER);
- (void) link_file (vfile, FILE_HOLDER);
- }
- else
- {
- ierrno = errno;
- fperror (logfp, 0, ierrno, "ERROR: cannot create link to %s", vfile);
- error (0, ierrno, "ERROR: cannot create link to %s", vfile);
- return (1);
- }
- }
- run_setup ("%s%s -q -f -r%s", Rcsbin, RCS_CI, vbranch);
- run_args ("-m%s", message);
- run_arg (rcs);
- status = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
- ierrno = errno;
- rename_file (FILE_HOLDER, vfile);
- if (status)
- {
- if (!noexec)
- {
- fperror (logfp, 0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs);
- error (0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs);
- }
- if (locked)
- {
- run_setup ("%s%s -q -u%s", Rcsbin, RCS, vbranch);
- run_arg (rcs);
- (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
- }
- return (1);
- }
- return (0);
- }
-
- /*
- * Add the vendor branch tag and all the specified import release tags to the
- * RCS file. The vendor branch tag goes on the branch root (1.1.1) while the
- * vendor release tags go on the newly added leaf of the branch (1.1.1.1,
- * 1.1.1.2, ...).
- */
- static int
- add_tags (rcs, vfile, vtag, targc, targv)
- char *rcs;
- char *vfile;
- char *vtag;
- int targc;
- char *targv[];
- {
- int i, ierrno;
- Vers_TS *vers;
- int retcode = 0;
-
- if (noexec)
- return (0);
-
- run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, vtag, vbranch);
- run_arg (rcs);
- if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
- {
- ierrno = errno;
- fperror (logfp, 0, retcode == -1 ? ierrno : 0,
- "ERROR: Failed to set tag %s in %s", vtag, rcs);
- error (0, retcode == -1 ? ierrno : 0,
- "ERROR: Failed to set tag %s in %s", vtag, rcs);
- return (1);
- }
- vers = Version_TS (repository, (char *) NULL, vtag, (char *) NULL, vfile,
- 1, 0, (List *) NULL, (List *) NULL);
- for (i = 0; i < targc; i++)
- {
- run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, targv[i], vers->vn_rcs);
- run_arg (rcs);
- if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
- {
- ierrno = errno;
- fperror (logfp, 0, retcode == -1 ? ierrno : 0,
- "WARNING: Couldn't add tag %s to %s", targv[i], rcs);
- error (0, retcode == -1 ? ierrno : 0,
- "WARNING: Couldn't add tag %s to %s", targv[i], rcs);
- }
- }
- freevers_ts (&vers);
- return (0);
- }
-
- /*
- * Stolen from rcs/src/rcsfnms.c, and adapted/extended.
- */
- struct compair
- {
- char *suffix, *comlead;
- };
-
- struct compair comtable[] =
- {
-
- /*
- * comtable pairs each filename suffix with a comment leader. The comment
- * leader is placed before each line generated by the $Log keyword. This
- * table is used to guess the proper comment leader from the working file's
- * suffix during initial ci (see InitAdmin()). Comment leaders are needed for
- * languages without multiline comments; for others they are optional.
- */
- "a", "-- ", /* Ada */
- "ada", "-- ",
- "asm", ";; ", /* assembler (MS-DOS) */
- "bat", ":: ", /* batch (MS-DOS) */
- "c", " * ", /* C */
- "c++", "// ", /* C++ in all its infinite guises */
- "cc", "// ",
- "cpp", "// ",
- "cxx", "// ",
- "cl", ";;; ", /* Common Lisp */
- "cmd", ":: ", /* command (OS/2) */
- "cmf", "c ", /* CM Fortran */
- "cs", " * ", /* C* */
- "csh", "# ", /* shell */
- "e", "# ", /* efl */
- "el", "; ", /* Emacs Lisp */
- "f", "c ", /* Fortran */
- "for", "c ",
- "h", " * ", /* C-header */
- "hh", "// ", /* C++ header */
- "hpp", "// ",
- "hxx", "// ",
- "in", "# ", /* for Makefile.in */
- "l", " * ", /* lex (conflict between lex and
- * franzlisp) */
- "mac", ";; ", /* macro (DEC-10, MS-DOS, PDP-11,
- * VMS, etc) */
- "me", ".\\\" ", /* me-macros t/nroff */
- "ml", "; ", /* mocklisp */
- "mm", ".\\\" ", /* mm-macros t/nroff */
- "ms", ".\\\" ", /* ms-macros t/nroff */
- "man", ".\\\" ", /* man-macros t/nroff */
- "1", ".\\\" ", /* feeble attempt at man pages... */
- "2", ".\\\" ",
- "3", ".\\\" ",
- "4", ".\\\" ",
- "5", ".\\\" ",
- "6", ".\\\" ",
- "7", ".\\\" ",
- "8", ".\\\" ",
- "9", ".\\\" ",
- "p", " * ", /* pascal */
- "pas", " * ",
- "pl", "# ", /* perl (conflict with Prolog) */
- "ps", "% ", /* postscript */
- "r", "# ", /* ratfor */
- "red", "% ", /* psl/rlisp */
- #ifdef sparc
- "s", "! ", /* assembler */
- #endif
- #ifdef mc68000
- "s", "| ", /* assembler */
- #endif
- #ifdef pdp11
- "s", "/ ", /* assembler */
- #endif
- #ifdef vax
- "s", "# ", /* assembler */
- #endif
- #ifdef __ksr__
- "s", "# ", /* assembler */
- "S", "# ", /* Macro assembler */
- #endif
- "sh", "# ", /* shell */
- "sl", "% ", /* psl */
- "tex", "% ", /* tex */
- "y", " * ", /* yacc */
- "ye", " * ", /* yacc-efl */
- "yr", " * ", /* yacc-ratfor */
- "", "# ", /* default for empty suffix */
- NULL, "# " /* default for unknown suffix; */
- /* must always be last */
- };
-
- static char *
- get_comment (user)
- char *user;
- {
- char *cp, *suffix;
- char suffix_path[PATH_MAX];
- int i;
-
- cp = rindex (user, '.');
- if (cp != NULL)
- {
- cp++;
-
- /*
- * Convert to lower-case, since we are not concerned about the
- * case-ness of the suffix.
- */
- (void) strcpy (suffix_path, cp);
- for (cp = suffix_path; *cp; cp++)
- if (isupper (*cp))
- *cp = tolower (*cp);
- suffix = suffix_path;
- }
- else
- suffix = ""; /* will use the default */
- for (i = 0;; i++)
- {
- if (comtable[i].suffix == NULL) /* default */
- return (comtable[i].comlead);
- if (strcmp (suffix, comtable[i].suffix) == 0)
- return (comtable[i].comlead);
- }
- }
-
- static int
- add_rcs_file (message, rcs, user, vtag, targc, targv)
- char *message;
- char *rcs;
- char *user;
- char *vtag;
- int targc;
- char *targv[];
- {
- FILE *fprcs, *fpuser;
- struct stat sb;
- struct tm *ftm;
- time_t now;
- char altdate1[50], altdate2[50];
- char *author, *buf;
- int i, mode, ierrno, err = 0;
-
- if (noexec)
- return (0);
-
- fprcs = open_file (rcs, "w+");
- fpuser = open_file (user, "r");
-
- /*
- * putadmin()
- */
- if (fprintf (fprcs, "head %s;\n", vhead) == EOF ||
- fprintf (fprcs, "branch %s;\n", vbranch) == EOF ||
- fprintf (fprcs, "access ;\n") == EOF ||
- fprintf (fprcs, "symbols ") == EOF)
- {
- goto write_error;
- }
-
- for (i = targc - 1; i >= 0; i--) /* RCS writes the symbols backwards */
- if (fprintf (fprcs, "%s:%s.1 ", targv[i], vbranch) == EOF)
- goto write_error;
-
- if (fprintf (fprcs, "%s:%s;\n", vtag, vbranch) == EOF ||
- fprintf (fprcs, "locks ; strict;\n") == EOF ||
- /* XXX - make sure @@ processing works in the RCS file */
- fprintf (fprcs, "comment @%s@;\n\n", get_comment (user)) == EOF)
- {
- goto write_error;
- }
-
- /*
- * puttree()
- */
- (void) time (&now);
- #ifdef HAVE_RCS5
- ftm = gmtime (&now);
- #else
- ftm = localtime (&now);
- #endif
- (void) sprintf (altdate1, DATEFORM,
- ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
- ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
- ftm->tm_min, ftm->tm_sec);
- now++;
- #ifdef HAVE_RCS5
- ftm = gmtime (&now);
- #else
- ftm = localtime (&now);
- #endif
- (void) sprintf (altdate2, DATEFORM,
- ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
- ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
- ftm->tm_min, ftm->tm_sec);
- author = getcaller ();
-
- if (fprintf (fprcs, "\n%s\n", vhead) == EOF ||
- fprintf (fprcs, "date %s; author %s; state Exp;\n",
- altdate1, author) == EOF ||
- fprintf (fprcs, "branches %s.1;\n", vbranch) == EOF ||
- fprintf (fprcs, "next ;\n") == EOF ||
- fprintf (fprcs, "\n%s.1\n", vbranch) == EOF ||
- fprintf (fprcs, "date %s; author %s; state Exp;\n",
- altdate2, author) == EOF ||
- fprintf (fprcs, "branches ;\n") == EOF ||
- fprintf (fprcs, "next ;\n\n") == EOF ||
- /*
- * putdesc()
- */
- fprintf (fprcs, "\ndesc\n") == EOF ||
- fprintf (fprcs, "@@\n\n\n") == EOF ||
- /*
- * putdelta()
- */
- fprintf (fprcs, "\n%s\n", vhead) == EOF ||
- fprintf (fprcs, "log\n") == EOF ||
- fprintf (fprcs, "@Initial revision\n@\n") == EOF ||
- fprintf (fprcs, "text\n@") == EOF)
- {
- goto write_error;
- }
-
- if (fstat (fileno (fpuser), &sb) < 0)
- error (1, errno, "cannot fstat %s", user);
- if (sb.st_size > 0)
- {
- off_t size;
-
- size = sb.st_size;
- buf = xmalloc ((int) size);
- if (fread (buf, (int) size, 1, fpuser) != 1)
- error (1, errno, "cannot read file %s for copying", user);
- if (expand_at_signs (buf, size, fprcs) == EOF)
- goto write_error;
- free (buf);
- }
- if (fprintf (fprcs, "@\n\n") == EOF ||
- fprintf (fprcs, "\n%s.1\n", vbranch) == EOF ||
- fprintf (fprcs, "log\n@") == EOF ||
- expand_at_signs (message, (off_t) strlen (message), fprcs) == EOF ||
- fprintf (fprcs, "@\ntext\n") == EOF ||
- fprintf (fprcs, "@@\n") == EOF)
- {
- goto write_error;
- }
- if (fclose (fprcs) == EOF)
- {
- ierrno = errno;
- goto write_error_noclose;
- }
- (void) fclose (fpuser);
-
- /*
- * Fix the modes on the RCS files. They must maintain the same modes as
- * the original user file, except that all write permissions must be
- * turned off.
- */
- mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH);
- if (chmod (rcs, mode) < 0)
- {
- ierrno = errno;
- fperror (logfp, 0, ierrno,
- "WARNING: cannot change mode of file %s", rcs);
- error (0, ierrno, "WARNING: cannot change mode of file %s", rcs);
- err++;
- }
- return (err);
-
- write_error:
- ierrno = errno;
- (void) fclose (fprcs);
- write_error_noclose:
- (void) fclose (fpuser);
- fperror (logfp, 0, ierrno, "ERROR: cannot write file %s", rcs);
- error (0, ierrno, "ERROR: cannot write file %s", rcs);
- if (ierrno == ENOSPC)
- {
- (void) unlink (rcs);
- fperror (logfp, 0, 0, "ERROR: out of space - aborting");
- error (1, 0, "ERROR: out of space - aborting");
- }
- return (err + 1);
- }
-
- /*
- * Sigh.. need to expand @ signs into double @ signs
- */
- static int
- expand_at_signs (buf, size, fp)
- char *buf;
- off_t size;
- FILE *fp;
- {
- char *cp, *end;
-
- for (cp = buf, end = buf + size; cp < end; cp++)
- {
- if (*cp == '@')
- (void) putc ('@', fp);
- if (putc (*cp, fp) == EOF)
- return (EOF);
- }
- return (1);
- }
-
- /*
- * Write an update message to (potentially) the screen and the log file.
- */
- static void
- add_log (ch, fname)
- char ch;
- char *fname;
- {
- if (!really_quiet) /* write to terminal */
- {
- if (repos_len)
- (void) printf ("%c %s/%s\n", ch, repository + repos_len + 1, fname);
- else if (repository[0])
- (void) printf ("%c %s/%s\n", ch, repository, fname);
- else
- (void) printf ("%c %s\n", ch, fname);
- }
-
- if (repos_len) /* write to logfile */
- (void) fprintf (logfp, "%c %s/%s\n", ch,
- repository + repos_len + 1, fname);
- else if (repository[0])
- (void) fprintf (logfp, "%c %s/%s\n", ch, repository, fname);
- else
- (void) fprintf (logfp, "%c %s\n", ch, fname);
- }
-
- /*
- * This is the recursive function that walks the argument directory looking
- * for sub-directories that have CVS administration files in them and updates
- * them recursively.
- *
- * Note that we do not follow symbolic links here, which is a feature!
- */
- static int
- import_descend_dir (message, dir, vtag, targc, targv)
- char *message;
- char *dir;
- char *vtag;
- int targc;
- char *targv[];
- {
- char cwd[PATH_MAX];
- char *cp;
- int ierrno, err;
-
- if (islink (dir))
- return (0);
- if (getwd (cwd) == NULL)
- {
- fperror (logfp, 0, 0, "ERROR: cannot get working directory: %s", cwd);
- error (0, 0, "ERROR: cannot get working directory: %s", cwd);
- return (1);
- }
- if (repository[0] == '\0')
- (void) strcpy (repository, dir);
- else
- {
- (void) strcat (repository, "/");
- (void) strcat (repository, dir);
- }
- if (!quiet)
- error (0, 0, "Importing %s", repository);
- if (chdir (dir) < 0)
- {
- ierrno = errno;
- fperror (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository);
- error (0, ierrno, "ERROR: cannot chdir to %s", repository);
- err = 1;
- goto out;
- }
- if (!isdir (repository))
- {
- if (isfile (repository))
- {
- fperror (logfp, 0, 0, "ERROR: %s is a file, should be a directory!",
- repository);
- error (0, 0, "ERROR: %s is a file, should be a directory!",
- repository);
- err = 1;
- goto out;
- }
- if (noexec == 0 && mkdir (repository, 0777) < 0)
- {
- ierrno = errno;
- fperror (logfp, 0, ierrno,
- "ERROR: cannot mkdir %s -- not added", repository);
- error (0, ierrno,
- "ERROR: cannot mkdir %s -- not added", repository);
- err = 1;
- goto out;
- }
- }
- err = import_descend (message, vtag, targc, targv);
- out:
- if ((cp = rindex (repository, '/')) != NULL)
- *cp = '\0';
- else
- repository[0] = '\0';
- if (chdir (cwd) < 0)
- error (1, errno, "cannot chdir to %s", cwd);
- return (err);
- }
-